package com.hfy.shop.service.impl;

import com.alibaba.fastjson.JSON;
import com.hfy.model.dto.order.CreateOrderDto;
import com.hfy.model.po.good.CommonGoodPo;
import com.hfy.model.po.order.OrderPo;
import com.hfy.model.vo.PopOrderVo;
import com.hfy.model.vo.order.WholeOrderVo;
import com.hfy.shop.mapper.GoodMapper;
import com.hfy.shop.mapper.OrderMapper;
import com.hfy.shop.service.OrderService;
import constants.RabbitConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import result.Result;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @ author 韩
 * time: 2024/9/10 16:24
 */

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private GoodMapper goodMapper;
    @Autowired
    private OrderMapper orderMapper;

    @Override
    @Transactional
    public Result creatOrder(CreateOrderDto dto) {
        // 这里先把订单持续事件设置成15秒
        // 1.1 先校验参数，看看该商品是否有库存
        CommonGoodPo good = goodMapper.queryGoodById(dto.getGoodId());
        if (good == null) return Result.error("已查询不到该商品");
        Boolean isPut = good.getIsPut();
        if (!isPut) return Result.error("无法对已下架的商品下订单");
        // 1.2 看看库存还够不够
        Boolean haveStore = good.getHaveStore();
        Integer store = good.getStore();
        if (haveStore && store <= 0) return Result.error("库存不足，无法下单");

        // 库存足就锁定一个库存
        if (haveStore) goodMapper.lockStore(good.getId());

        // 1.3 todo 如果有一个人只能买一单等等限制，可继续扩展

        // 2.1 然后就要生成订单的信息了，比如订单的id，这里起始应该使用杂乱的数字字母等作为id，图方便就直接使用自增id

        // 2.2 然后生成开始时间和结束时间
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime end = LocalDateTime.now().plusMinutes(15); // 15分钟写死
        PopOrderVo popOrderVo = new PopOrderVo(null, good.getId(), now, end, 15 * 60, dto.getAccount());
        orderMapper.creatOrder(popOrderVo);

        // 3 准备对象，发送消息
        String mes = JSON.toJSONString(popOrderVo);
        sendDelayMessage(mes, 60 * 15, RabbitConstants.DELAY_ORDER_DEL_DIRECT_EXCHANGE, RabbitConstants.DELAY_ORDER_KEY);


        // 然后封装一下给前端，然后前端得到信息后，弹出弹出层，在我的订单里也可以找到该信息
        return Result.ok(popOrderVo);
    }

    @Override
    public Result getOrderListByStatus(String status, Long account) {

        List<WholeOrderVo> orderList = orderMapper.getOrderListByStatus(status, account);

        // 还需要根据订单去查商品里的数据
        orderList.forEach(orderVo -> {
            Integer goodId = orderVo.getGoodId();
            CommonGoodPo good = goodMapper.queryGoodById(goodId);
            orderVo.setCover(good.getCover());
            orderVo.setTitle(good.getTitle());
            orderVo.setOriginPrice(good.getOriginPrice());
            orderVo.setSalePrice(good.getSalePrice());
            orderVo.setPayType(good.getPayType());
        });

        return Result.ok(orderList);
    }

    @Override
    public Result getOrderInfo(String id) {
        // 校验参数
        Integer orderId;
        try {
            orderId = Integer.valueOf(id);
        } catch (Exception e) {
            throw new RuntimeException("订单号只能为数字");
        }
        // 去根据id查订单详情
        OrderPo orderInfo = orderMapper.getOrderInfo(orderId);
        if (orderInfo == null) return Result.error("该订单异常");
        return Result.ok(orderInfo);
    }

    private void sendDelayMessage(String mes, Integer delaySeconds, String exchange, String key) {
        Message message = MessageBuilder
                .withBody(mes.getBytes(StandardCharsets.UTF_8))
                .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
                .setHeader("x-delay", delaySeconds * 1000)
                .build();

        rabbitTemplate.convertAndSend(exchange, key, message);

    }
}
